<?php
/**
 * Hooks for Conversations.
 *
 * @copyright 2009-2019 Vanilla Forums Inc.
 * @license GPL-2.0-only
 * @package Conversations
 * @since 2.0
 */

use Garden\Container\Container;
use Garden\Container\Reference;
use Vanilla\Conversations\Layout\LegacyMessageInboxLayoutView;
use Vanilla\Dashboard\Layout\View\LegacyProfileLayoutView;
use Vanilla\Layout\LayoutService;

/**
 * Handles hooks into Dashboard and Vanilla.
 */
class ConversationsHooks implements Gdn_IPlugin
{
    /**
     * Handle the container init event to register things with the container.
     *
     * @param Container $dic
     */
    public function container_init(Container $dic)
    {
        $dic->rule(\Vanilla\Menu\CounterModel::class)->addCall("addProvider", [
            new Reference(ConversationCounterProvider::class),
        ]);
        $dic->rule(LayoutService::class)->addCall("addLayoutView", [
            new Reference(LegacyMessageInboxLayoutView::class),
        ]);

        $dic->rule(\Vanilla\Dashboard\Models\ActivityService::class)
            ->addCall("registerActivity", [\Activity\ConversationMessageActivity::class])
            ->addCall("registerActivity", [\Activity\AddedToConversationActivity::class]);
    }

    /**
     *
     *
     * @param DbaController $sender
     */
    public function dbaController_countJobs_handler($sender)
    {
        $counts = [
            "Conversation" => [
                "CountMessages",
                "CountParticipants",
                "FirstMessageID",
                "LastMessageID",
                "DateUpdated",
                "UpdateUserID",
            ],
        ];

        foreach ($counts as $table => $columns) {
            foreach ($columns as $column) {
                $name = "Recalculate $table.$column";
                $url = "/dba/counts.json?" . http_build_query(["table" => $table, "column" => $column]);

                $sender->Data["Jobs"][$name] = $url;
            }
        }
    }

    /**
     * Remove data when deleting a user.
     *
     * @since 2.0.0
     * @access public
     */
    public function userModel_beforeDeleteUser_handler($sender)
    {
        $userID = val("UserID", $sender->EventArguments);
        $options = val("Options", $sender->EventArguments, []);
        $options = is_array($options) ? $options : [];

        $deleteMethod = val("DeleteMethod", $options, "delete");
        if ($deleteMethod == "delete") {
            /** @var Gdn_SQLDriver $sql */
            $sql = $sender->SQL;
            $sql->from("UserConversation as uc")
                ->join("Conversation as c", "c.ConversationID = uc.ConversationID")
                ->where(["c.InsertUserID" => $userID])
                ->orWhere(["c.UpdateUserID" => $userID])
                ->delete();
            $sql->from("ConversationMessage as cm")
                ->join("Conversation as c", "c.ConversationID = cm.ConversationID")
                ->where(["c.InsertUserID" => $userID])
                ->orWhere(["c.UpdateUserID" => $userID])
                ->delete();

            $sender->SQL->delete("Conversation", ["InsertUserID" => $userID]);
            $sender->SQL->delete("Conversation", ["UpdateUserID" => $userID]);
        } elseif ($deleteMethod == "wipe") {
            $sender->SQL
                ->update("ConversationMessage")
                ->set("Body", t("The user and all related content has been deleted."))
                ->set("Format", "Deleted")
                ->where("InsertUserID", $userID)
                ->put();
        }
        // Remove the user's profile information related to this application
        $sender->SQL
            ->update("User")
            ->set("CountUnreadConversations", 0)
            ->where("UserID", $userID)
            ->put();
    }

    /**
     * Add 'Inbox' to profile menu.
     *
     * @since 2.0.0
     * @access public
     */
    public function profileController_addProfileTabs_handler($sender)
    {
        if (Gdn::session()->isValid()) {
            $inbox = t("Inbox");
            $inboxHtml = sprite("SpInbox") . " " . $inbox;
            $inboxLink = "/messages/all";

            if (Gdn::session()->UserID != $sender->User->UserID) {
                // Accomodate admin access
                if (
                    c("Conversations.Moderation.Allow", false) &&
                    Gdn::session()->checkPermission("Conversations.Moderation.Manage")
                ) {
                    $countUnread = $sender->User->CountUnreadConversations;
                    $inboxLink .= "?userid={$sender->User->UserID}";
                } else {
                    return;
                }
            } else {
                // Current user
                $countUnread = Gdn::session()->User->CountUnreadConversations;
            }

            if (is_numeric($countUnread) && $countUnread > 0) {
                $inboxHtml .= ' <span class="Aside"><span class="Count">' . $countUnread . "</span></span>";
            }
            $sender->addProfileTab($inbox, $inboxLink, "Inbox", $inboxHtml);
        }
    }

    /**
     * Add "Message" option to profile options.
     */
    public function profileController_beforeProfileOptions_handler($sender, $args)
    {
        if (
            !$sender->EditMode &&
            Gdn::session()->UserID != $sender->User->UserID &&
            Gdn::session()->checkPermission("Conversations.Conversations.Add")
        ) {
            $sender->EventArguments["MemberOptions"][] = [
                "Text" => sprite("SpMessage") . " " . t("Message"),
                "Url" => "/messages/add/" . rawurlencode($sender->User->Name),
                "CssClass" => "MessageUser",
            ];
        }
    }

    /**
     * Additional options for the Preferences screen.
     *
     * @since 2.0.0
     * @access public
     */
    public function profileController_afterPreferencesDefined_handler($sender)
    {
        $sender->Preferences["Notifications"]["Email.ConversationMessage"] = t("Notify me of private messages.");
        $sender->Preferences["Notifications"]["Popup.ConversationMessage"] = t("Notify me of private messages.");
    }

    /**
     * Add 'Inbox' to global menu.
     *
     * @since 2.0.0
     * @access public
     */
    public function base_render_before($sender)
    {
        // Add the menu options for conversations
        if ($sender->Menu && Gdn::session()->isValid()) {
            $inbox = t("Inbox");
            $countUnreadConversations = val("CountUnreadConversations", Gdn::session()->User);
            if (is_numeric($countUnreadConversations) && $countUnreadConversations > 0) {
                $inbox .= ' <span class="Alert">' . $countUnreadConversations . "</span>";
            }

            $sender->Menu->addLink("Conversations", $inbox, "/messages/all", false, ["Standard" => true]);
        }
    }

    /**
     * Provide default permissions for roles, based on the value in their Type column.
     *
     * @param PermissionModel $sender Instance of permission model that fired the event
     */
    public function permissionModel_defaultPermissions_handler($sender)
    {
        $sender->addDefault(RoleModel::TYPE_MEMBER, ["Conversations.Conversations.Add" => 1]);
        $sender->addDefault(RoleModel::TYPE_MODERATOR, ["Conversations.Conversations.Add" => 1]);
        $sender->addDefault(RoleModel::TYPE_ADMINISTRATOR, ["Conversations.Conversations.Add" => 1]);
    }

    /**
     * Database & config changes to be done upon enable.
     *
     * @since 2.0.0
     * @access public
     */
    public function setup()
    {
        $Database = Gdn::database();
        $Config = Gdn::factory(Gdn::AliasConfig);
        $Drop = false;
        $Validation = new Gdn_Validation(); // This is going to be needed by structure.php to validate permission names
        include PATH_APPLICATIONS . DS . "conversations" . DS . "settings" . DS . "structure.php";
        include PATH_APPLICATIONS . DS . "conversations" . DS . "settings" . DS . "stub.php";
    }
}
